package io.esirong.base.mvp;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import io.esirong.util.BusUtils;

/**
 * 实现了常用的的方法和定义常用的对象。
 *
 * @param <M>
 * @param <V>
 */
public abstract class BasePresenter<M extends IBaseModel, V extends IBaseView> implements IBasePresenter<V,M> {
    private V mProxyView;
    private M module;
    private WeakReference<V> weakReference;

    @Override
    public void start() {

    }

    /**
     * 通过该方法创建Module
     */
    protected abstract M createModule();

    @Override
    public <P> void attachView(V view) {
        registerBus();
        weakReference = new WeakReference<>(view);

        mProxyView = (V) Proxy.newProxyInstance(
                view.getClass().getClassLoader(),
                view.getClass().getInterfaces(),
                new MvpViewHandler(weakReference.get()));

        if (this.module == null) {
            this.module = createModule();
        }
    }

    @Override
    public <P> void detachView(V view) {
        unregisterBus();
        this.module = null;
        if (isViewAttached()) {
            weakReference.clear();
            weakReference = null;
        }
    }

    @Override
    public V getView() {
        return mProxyView;
    }

    @Override
    public M getModel() {
        return module;
    }

    @Override
    public String getString(int id) {
        return getView().getContextX().getString(id);
    }

    /**
     * 需要接收事件 重写该方法 并返回true
     */
    protected boolean regEvent() {
        return false;
    }

    private void registerBus() {
        if (regEvent()) {
            BusUtils.register(this);
        }
    }

    private void unregisterBus() {
        if (regEvent()) {
            BusUtils.unregister(this);
        }
    }

    /**
     * 是否与View建立连接
     */
    protected boolean isViewAttached() {
        return weakReference != null && weakReference.get() != null;
    }

    /**
     * View代理类  防止 页面关闭P异步操作调用V 方法 空指针问题
     */
    private class MvpViewHandler implements InvocationHandler {

        private IBaseView mvpView;

        MvpViewHandler(IBaseView mvpView) {
            this.mvpView = mvpView;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //如果V层没被销毁, 执行V层的方法.
            if (isViewAttached()) {
                return method.invoke(mvpView, args);
            } //P层不需要关注V层的返回值
            return null;
        }
    }
}